1 using System;
2 using
System.Collections.Generic;
3 using
ExitGames.Client.Photon.Chat;
4 using
UnityEngine;
5
6
7 ///
<summary>
8 ///
This simple Chat Server Gui uses a global chat (in lobby) and a room chat (in room).
9 ///
</summary>
10 ///
<remarks>
11 ///
The Chat Server API in ChatClient basically lets you create any number of channels.
12 ///
You just have to name them. Example: "gc" for Global Channel or for rooms: "rc"+RoomName.GetHashCode()
13 ///

14 ///
This simple demo sends in a global chat when in lobby and in room channel when in room.
15 ///
Create a more elaborate UI to let players chat in either channel while in room or send private messages.
16 ///

17 ///
Names of users are set in Authenticate. That should be unique so users can actually get their messages.
18 ///

19 ///

20 ///
Workflow:
21 ///
Create ChatClient, Connect to a server with your AppID, Authenticate the user (apply a unique name)
22 ///
and subscribe to some channels.
23 ///
Subscribe a channel before you publish to that channel!
24 ///

25 ///

26 ///
Note:
27 ///
Don't forget to call ChatClient.Service(). Might later on be integrated into PUN but for now don't forget.
28 ///
</remarks>
29 public
class ChatGui : MonoBehaviour, IChatClientListener
30 {
31     
public string ChatAppId; // set in inspector. Your Chat AppId (don't mix it with Realtime/Turnbased Apps).
32     
public string[] ChannelsToJoinOnConnect; // set in inspector. Demo channels to join automatically.
33     
public int HistoryLengthToFetch; // set in inspector. Up to a certain degree, previously sent messages can be fetched for context.
34     
public bool DemoPublishOnSubscribe; // set in inspector. For demo purposes, we publish a default text to any subscribed channel.
35
36     
public string UserName { get; set; }
37
38     
private ChatChannel selectedChannel;
39     
private string selectedChannelName; // mainly used for GUI/input
40     
private int selectedChannelIndex = 0; // mainly used for GUI/input
41     
bool doingPrivateChat;
42     
43     
44     
public ChatClient chatClient;
45     
46     
// GUI stuff:
47     
public Rect GuiRect = new Rect(0, 0, 250, 300);
48     
public bool IsVisible = true;
49     
public bool AlignBottom = false;
50     
public bool FullScreen = false;
51
52     
private string inputLine = "";
53     
private string userIdInput = "";
54     
private Vector2 scrollPos = Vector2.zero;
55     
private static string WelcomeText = "Welcome to chat.\\help lists commands.";
56     
private static string HelpText = "\n\\subscribe <list of channelnames> subscribes channels.\n\\unsubscribe <list of channelnames> leaves channels.\n\\msg <username> <message> send private message to user.\n\\clear clears the current chat tab. private chats get closed.\n\\help gets this help message.";
57
58     
public void Start()
59     {
60         DontDestroyOnLoad(
this.gameObject);
61         Application.runInBackground =
true; // this must run in background or it will drop connection if not focussed.
62
63         
if (string.IsNullOrEmpty(this.UserName))
64         {
65             
this.UserName = "user" + Environment.TickCount%99; //made-up username
66         }
67
68         chatClient =
new ChatClient(this);
69         chatClient.Connect(ChatAppId,
"1.0", this.UserName, null);
70
71         
if (this.AlignBottom)
72         {
73             
this.GuiRect.y = Screen.height - this.GuiRect.height;
74         }
75         
if (this.FullScreen)
76         {
77             
this.GuiRect.x = 0;
78             
this.GuiRect.y = 0;
79             
this.GuiRect.width = Screen.width;
80             
this.GuiRect.height = Screen.height;
81         }
82
83         Debug.Log(
this.UserName);
84     }

85
86     ///
<summary>To avoid that the Editor becomes unresponsive, disconnect all Photon connections in OnApplicationQuit.</summary>
87     
public void OnApplicationQuit()
88     {
89         
if (this.chatClient != null)
90         {
91             
this.chatClient.Disconnect();
92         }
93     }
94
95     
public void Update()
96     {
97         
if (this.chatClient != null)
98         {
99             
this.chatClient.Service(); // make sure to call this regularly! it limits effort internally, so calling often is ok!
100         }
101     }
102
103     
public void OnGUI()
104     {
105         
if (!this.IsVisible)
106         {
107             
return;
108         }
109
110         GUI.skin.label.wordWrap =
true;
111         
//GUI.skin.button.richText = true; // this allows toolbar buttons to have bold/colored text. nice to indicate new msgs
112         
//GUILayout.Button("<b>lala</b>"); // as richText, html tags could be in text
113
114
115         
if (Event.current.type == EventType.KeyDown && (Event.current.keyCode == KeyCode.KeypadEnter || Event.current.keyCode == KeyCode.Return))
116         {
117             
if ("ChatInput".Equals(GUI.GetNameOfFocusedControl()))
118             {
119                 
// focus on input -> submit it
120                 GuiSendsMsg();
121                 
return; // showing the now modified list would result in an error. to avoid this, we just skip this single frame
122             }
123             
else
124             {
125                 
// assign focus to input
126                 GUI.FocusControl(
"ChatInput");
127             }
128         }
129
130         GUI.SetNextControlName(
"");
131         GUILayout.BeginArea(
this.GuiRect);
132
133         GUILayout.FlexibleSpace();
134
135         
if (this.chatClient.State != ChatState.ConnectedToFrontEnd)
136         {
137             GUILayout.Label(
"Not in chat yet.");
138         }
139         
else
140         {
141             List<
string> channels = new List<string>(this.chatClient.PublicChannels.Keys); // this could be cached
142             
int countOfPublicChannels = channels.Count;
143             channels.AddRange(
this.chatClient.PrivateChannels.Keys);
144
145             
if (channels.Count > 0)
146             {
147                 
int previouslySelectedChannelIndex = this.selectedChannelIndex;
148                 
int channelIndex = channels.IndexOf(this.selectedChannelName);
149                 
this.selectedChannelIndex = (channelIndex >= 0) ? channelIndex : 0;
150                 
151                 
this.selectedChannelIndex = GUILayout.Toolbar(this.selectedChannelIndex, channels.ToArray(), GUILayout.ExpandWidth(false));
152                 
this.scrollPos = GUILayout.BeginScrollView(this.scrollPos);
153
154                 
this.doingPrivateChat = (this.selectedChannelIndex >= countOfPublicChannels);
155                 
this.selectedChannelName = channels[this.selectedChannelIndex];
156
157                 
if (this.selectedChannelIndex != previouslySelectedChannelIndex)
158                 {
159                     
// changed channel -> scroll down, if private: pre-fill "to" field with target user's name
160                     
this.scrollPos.y = float.MaxValue;
161                     
if (this.doingPrivateChat)
162                     {
163                         
string[] pieces = this.selectedChannelName.Split(new char[] {':'}, 3);
164                         
this.userIdInput = pieces[1];
165                     }
166                 }
167
168                 GUILayout.Label(ChatGui.WelcomeText);
169
170                 
if (this.chatClient.TryGetChannel(selectedChannelName, this.doingPrivateChat, out this.selectedChannel))
171                 {
172                     
for (int i = 0; i < this.selectedChannel.Messages.Count; i++)
173                     {
174                         
string sender = this.selectedChannel.Senders[i];
175                         
object message = this.selectedChannel.Messages[i];
176                         GUILayout.Label(
string.Format("{0}: {1}", sender, message));
177                     }
178                 }
179
180                 GUILayout.EndScrollView();
181             }
182         }
183
184
185         GUILayout.BeginHorizontal();
186         
if (doingPrivateChat)
187         {
188             GUILayout.Label(
"to:", GUILayout.ExpandWidth(false));
189             GUI.SetNextControlName(
"WhisperTo");
190             
this.userIdInput = GUILayout.TextField(this.userIdInput, GUILayout.MinWidth(100), GUILayout.ExpandWidth(false));
191             
string focussed = GUI.GetNameOfFocusedControl();
192             
if (focussed.Equals("WhisperTo"))
193             {
194                 
if (this.userIdInput.Equals("username"))
195                 {
196                     
this.userIdInput = "";
197                 }
198             }
199             
else if (string.IsNullOrEmpty(this.userIdInput))
200             {
201                 
this.userIdInput = "username";
202             }
203
204         }
205         GUI.SetNextControlName(
"ChatInput");
206         inputLine = GUILayout.TextField(inputLine);
207         
if (GUILayout.Button("Send", GUILayout.ExpandWidth(false)))
208         {
209             GuiSendsMsg();
210         }
211         GUILayout.EndHorizontal();
212         GUILayout.EndArea();
213     }
214
215     
private void GuiSendsMsg()
216     {
217         
if (string.IsNullOrEmpty(this.inputLine))
218         {
219
220             GUI.FocusControl(
"");
221             
return;
222         }
223
224         
if (this.inputLine[0].Equals('\\'))
225         {
226             
string[] tokens = this.inputLine.Split(new char[] {' '}, 2);
227             
if (tokens[0].Equals("\\help"))
228             {
229                 
this.PostHelpToCurrentChannel();
230             }
231             
if (tokens[0].Equals("\\state"))
232             {
233                 
int newState = int.Parse(tokens[1]);
234                 
this.chatClient.SetOnlineStatus(newState, new string[] { "i am state " + newState }); // this is how you set your own state and (any) message
235             }
236             
else if (tokens[0].Equals("\\subscribe") && !string.IsNullOrEmpty(tokens[1]))
237             {
238                 
this.chatClient.Subscribe(tokens[1].Split(new char[] {' ', ','}));
239             }
240             
else if (tokens[0].Equals("\\unsubscribe") && !string.IsNullOrEmpty(tokens[1]))
241             {
242                 
this.chatClient.Unsubscribe(tokens[1].Split(new char[] {' ', ','}));
243             }
244             
else if (tokens[0].Equals("\\clear"))
245             {
246                 
if (this.doingPrivateChat)
247                 {
248                     
this.chatClient.PrivateChannels.Remove(this.selectedChannelName);
249                 }
250                 
else
251                 {
252                     ChatChannel channel;
253                     
if (this.chatClient.TryGetChannel(this.selectedChannelName, this.doingPrivateChat, out channel))
254                     {
255                         channel.ClearMessages();
256                     }
257                 }
258             }
259             
else if (tokens[0].Equals("\\msg") && !string.IsNullOrEmpty(tokens[1]))
260             {
261                 
string[] subtokens = tokens[1].Split(new char[] {' ', ','}, 2);
262                 
string targetUser = subtokens[0];
263                 
string message = subtokens[1];
264                 
this.chatClient.SendPrivateMessage(targetUser, message);
265             }
266         }
267         
else
268         {
269             
if (this.doingPrivateChat)
270             {
271                 
this.chatClient.SendPrivateMessage(this.userIdInput, this.inputLine);
272             }
273             
else
274             {
275                 
this.chatClient.PublishMessage(this.selectedChannelName, this.inputLine);
276             }
277         }
278
279         
this.inputLine = "";
280         GUI.FocusControl(
"");
281     }
282
283     
private void PostHelpToCurrentChannel()
284     {
285         ChatChannel channelForHelp =
this.selectedChannel;
286         
if (channelForHelp != null)
287         {
288             channelForHelp.Add(
"info", ChatGui.HelpText);
289         }
290         
else
291         {
292             Debug.LogError(
"no channel for help");
293         }
294     }
295
296     
public void OnConnected()
297     {
298         
if (this.ChannelsToJoinOnConnect != null && this.ChannelsToJoinOnConnect.Length > 0)
299         {
300             
this.chatClient.Subscribe(this.ChannelsToJoinOnConnect, this.HistoryLengthToFetch);
301         }
302
303         
this.chatClient.AddFriends(new string[] {"tobi", "ilya"}); // Add some users to the server-list to get their status updates
304         
this.chatClient.SetOnlineStatus(ChatUserStatus.Online); // You can set your online state (without a mesage).
305     }
306     
307     
public void OnDisconnected()
308     {
309     }
310
311     
public void OnChatStateChange(ChatState state)
312     {
313         
// use OnConnected() and OnDisconnected()
314         
// this method might become more useful in the future, when more complex states are being used.
315     }
316
317     
public void OnSubscribed(string[] channels, bool[] results)
318     {
319      
320         
// this demo can automatically send a "hi" to subscribed channels. in a game you usually only send user's input!!
321         
if (this.DemoPublishOnSubscribe)
322         {
323             
foreach (string channel in channels)
324             {
325                 
this.chatClient.PublishMessage(channel, "says 'hi' in OnSubscribed(). "); // you don't HAVE to send a msg on join but you could.
326             }
327         }
328     }
329     
330     
public void OnUnsubscribed(string[] channels)
331     {
332     }
333
334     
public void OnGetMessages(string channelName, string[] senders, object[] messages)
335     {
336         
if (channelName.Equals(this.selectedChannelName))
337         {
338             
this.scrollPos.y = float.MaxValue;
339         }
340     }
341
342     
public void OnPrivateMessage(string sender, object message, string channelName)
343     {
344         
// as the ChatClient is buffering the messages for you, this GUI doesn't need to do anything here
345         
// you also get messages that you sent yourself. in that case, the channelName is determinded by the target of your msg
346     }
347     
348     
public void OnStatusUpdate(string user, int status, bool gotMessage, object message)
349     {
350         
// this is how you get status updates of friends.
351         
// this demo simply adds status updates to the currently shown chat.
352         
// you could buffer them or use them any other way, too.
353
354         ChatChannel activeChannel =
this.selectedChannel;
355         
if (activeChannel != null)
356         {
357             activeChannel.Add(
"info", string.Format("{0} is {1}. Msg:{2}", user, status, message));
358         }
359         
360         Debug.LogWarning(
"status: " + string.Format("{0} is {1}. Msg:{2}", user, status, message));
361     }
362 }


This simple Chat Server Gui uses a global chat (in lobby) and a room chat (in room).

The Chat Server API in ChatClient basically lets you create any number of channels.

You just have to name them. Example: "gc" for Global Channel or for rooms: "rc"+RoomName.GetHashCode()

This simple demo sends in a global chat when in lobby and in room channel when in room.

Create a more elaborate UI to let players chat in either channel while in room or send private messages.

Names of users are set in Authenticate. That should be unique so users can actually get their messages.

Workflow:

Create ChatClient, Connect to a server with your AppID, Authenticate the user (apply a unique name)

and subscribe to some channels.

Subscribe a channel before you publish to that channel!

Note:

Don't forget to call ChatClient.Service(). Might later on be integrated into PUN but for now don't forget.

public string ChatAppId; set in inspector. Your Chat AppId (don't mix it with RealtimeTurnbased Apps).

public string[] ChannelsToJoinOnConnect; set in inspector. Demo channels to join automatically.

public int HistoryLengthToFetch; set in inspector. Up to a certain degree, previously sent messages can be fetched for context.

public bool DemoPublishOnSubscribe; set in inspector. For demo purposes, we publish a default text to any subscribed channel.

private string selectedChannelName; mainly used for GUIinput

private int selectedChannelIndex = 0; mainly used for GUIinput

GUI stuff:

Application.runInBackground = true; this must run in background or it will drop connection if not focussed.

this.UserName = "user" + Environment.TickCount%99; made-up username

To avoid that the Editor becomes unresponsive, disconnect all Photon connections in OnApplicationQuit.

this.chatClient.Service(); make sure to call this regularly! it limits effort internally, so calling often is ok!

GUI.skin.button.richText = true; this allows toolbar buttons to have boldcolored text. nice to indicate new msgs

GUILayout.Button("lala"); as richText, html tags could be in text

focus on input -> submit it

return; showing the now modified list would result in an error. to avoid this, we just skip this single frame

assign focus to input

List channels = new List(this.chatClient.PublicChannels.Keys); this could be cached

changed channel -> scroll down, if private: pre-fill "to" field with target user's name

this.chatClient.SetOnlineStatus(newState, new string[] { "i am state " + newState }); this is how you set your own state and (any) message

this.chatClient.AddFriends(new string[] {"tobi", "ilya"}); Add some users to the server-list to get their status updates

this.chatClient.SetOnlineStatus(ChatUserStatus.Online); You can set your online state (without a mesage).

use OnConnected() and OnDisconnected()

this method might become more useful in the future, when more complex states are being used.

this demo can automatically send a "hi" to subscribed channels. in a game you usually only send user's input!!

this.chatClient.PublishMessage(channel, "says 'hi' in OnSubscribed(). "); you don't HAVE to send a msg on join but you could.

as the ChatClient is buffering the messages for you, this GUI doesn't need to do anything here

you also get messages that you sent yourself. in that case, the channelName is determinded by the target of your msg

this is how you get status updates of friends.

this demo simply adds status updates to the currently shown chat.

you could buffer them or use them any other way, too.




Trò chơi Tic-Tac-Toe, game đánh caro full source code 53.481 lượt xem

Gõ tìm kiếm nhanh...